<template>
  <div :class="schema.commonFormControlClass" class="input-combo" :disabled="disabled" @click="toggleMenu" @keydown="quickKey">
    <div class="input-combo-label">{{formattedValue}}</div>
    <i class="right-icon fa fa-caret-down"></i>
    <grid-panel v-show="menuVisible" :dataSource="dataSource" :config="field" @selectionChange="selectionChange" ref="gridPanel"></grid-panel>
  </div>
</template>
<script>
  import _ from 'lodash'
  import Utils from '../../utils'
  import GridPanel from './GridPanel.vue'

  let setMenuState = function (vm, visible) {
    vm.menuVisible = visible
    if (!visible) {
      vm.$refs.gridPanel && vm.$refs.gridPanel.clearFocusState()
      Utils.off(document, 'click', vm.documentClickHandler)
    } else {
      Utils.off(document, 'click', vm.documentClickHandler)
      Utils.on(document, 'click', vm.documentClickHandler)
    }
  }

  export default {
    components: { GridPanel },
    props: {
      schema: {
        type: Object,
        default () {
          return {}
        }
      },
      value: {},
      field: Object,
      disabled: Boolean,
      dataSource: {
        type: Array,
        default: []
      }
    },
    data () {
      let vm = this
      return {
        curSelectionNodes: [],
        menuVisible: false,
        lastValue: null,
        documentClickHandler (evt) {
          if (!vm.$el.contains(evt.target)) {
            setMenuState(vm, false)
          }
        }
      }
    },
    computed: {
      formattedValue () {
        if (this.field.comboRenderer) {
          if (!(this.field.comboRenderer instanceof Function)) {
            throw new Error('comboRenderer must be function...')
          }
          return this.field.comboRenderer(this.curSelectionNodes)
        }
        return _.chain(this.curSelectionNodes).map(node => {
          let val
          if (!_.isNil(this.field.comboDisplayRenderer)) {
            val = this.field.comboDisplayRenderer(node)
          } else if (!_.isNil(this.field.comboDisplayProp)) {
            val = _.get(node, this.field.comboDisplayProp)
          } else {
            val = node.$data
          }
          return val
        }).join(',').value()
      }
    },
    mounted () {
      this.$nextTick(() => {
        this.$refs.gridPanel.setSelectedValues(
          this.field.comboMultiSelection ? this.value : _.isNil(this.value) ? [] : [this.value]
        )
      })
    },
    watch: {
      value: function (v, oldV) {
        if (_.isNil(v) && _.isNil(this.lastValue)) {
          return
        }
        if (this.field.comboMultiSelection) {
          if (!_.isEqual(_.sortBy(v), _.sortBy(this.lastValue))) {
            this.$refs.gridPanel.setSelectedValues(v)
          }
        } else {
          if (!_.isEqual(v, this.lastValue)) {
            this.$refs.gridPanel.setSelectedValues([v])
          }
        }
      }
    },
    methods: {
      selectionChange (nodes) {
        this.curSelectionNodes = nodes
        let val = null
        if (nodes.length === 0) {
          val = null
        } else {
          val = _.map(nodes, node => {
            if (!_.isNil(this.field.comboValueProp)) {
              return _.get(node.$data, this.field.comboValueProp)
            } else {
              return node.$data
            }
          })
          if (!this.field.comboMultiSelection) {
            val = _.head(val)
          }
        }
        this.lastValue = val
        this.$emit('input', val)

        if (!this.field.comboMultiSelection) {
          setMenuState(this, false)
        }
      },
      openMenu () {
        setMenuState(this, true)
      },
      toggleMenu (e) {
        if (!this.disabled && !this.$refs.gridPanel.$el.contains(e.target)) {
          setMenuState(this, !this.menuVisible)
        }
      },
      quickKey (e) {
        if (this.disabled) {
          return
        }
        let keyCode = e.keyCode ? e.keyCode : e.which
        console.log('key?', keyCode)
        if (keyCode === 9 || keyCode === 27) {
          setMenuState(this, false)
          return
        }
        // A all selection
        if (keyCode === 65) {
          this.$refs.gridPanel.quickKey(keyCode, e)

          e.preventDefault()
          e.stopPropagation()
          return false
        }
        if (e.altKey || e.ctrlKey || e.shiftKey) {
          return
        }
        if (keyCode === 13) {
          // TODO cannt submit
          console.log('...')
          this.$emit('submit', e)
          return
        }
        switch (keyCode) {
          case 39: // right
            if (this.$refs.gridPanel.quickKey(keyCode) === false) {
              setMenuState(this, true)
            }
            break
          case 37: // left
            if (this.$refs.gridPanel.quickKey(keyCode) === false) {
              setMenuState(this, false)
            }
            break
          case 27: // esc
            setMenuState(this, false)
            break
          case 32: // blank space
          case 38: // up
          case 40: // down
            this.$refs.gridPanel.quickKey(keyCode)
            break
        }
        e.preventDefault()
        e.stopPropagation()
      }
    }
  }
</script>

<style lang="scss" scoped>
  .input-combo {
    position: relative;
    cursor: default;
    &[disabled] {
      cursor: not-allowed;

      &:focus {
        outline: none;
        box-shadow: none;
        border: 1px solid #ccc;
      }
    }

    .input-combo-label {
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }

    .right-icon {
      position: absolute;
      right: 4px;
      top: 8px;
    }

    .grid-panel{
      min-height: 54px;
      top: 33px;
      left: -1px;
      right: -1px;
      padding: 4px 10px;
    }
  }
</style>
